<?php

declare(strict_types=1);

namespace sheep\console;

use think\console\input\Argument;
use think\console\input\Option;
use Exception;
use sheep\exception\SheepException;
use sheep\library\console\Composer as ComposerProcess;
use sheep\library\install\Install;
use app\admin\model\auth\Admin;
use sheep\library\ratelimiter\RateLimiter;
use sheep\library\install\traits\Env;
use think\facade\Db;
use sheep\traits\DatabaseOper;
use sheep\library\markdown\traits\DatabaseNotes;
use sheep\traits\ClearCache;
use think\facade\Queue;

class SheepHelp extends Command
{
    use Env, DatabaseOper, DatabaseNotes, ClearCache;

    protected $input = null;
    protected $output = null;

    /**
     * 支持的命令列表
     */
    protected $commands = [
        ['code' => "0", 'name' => 'cancel', 'desc' => '取消'],
        ['code' => "1", 'name' => 'all', 'desc' => 'sheep 帮助工具列表'],
        ['code' => "2", 'name' => 'open_debug', 'desc' => '开启 debug'],
        ['code' => "3", 'name' => 'close_debug', 'desc' => '关闭 debug'],
        ['code' => "4", 'name' => 'admin_reset_password', 'desc' => '重置管理员密码'],
        ['code' => "5", 'name' => 'admin_clear_login_fail', 'desc' => '清除管理员登录锁定状态'],
        ['code' => "6", 'name' => 'database_notes_md', 'desc' => '生成 markdown 格式的数据库字典'],
        ['code' => "7", 'name' => 'database_notes_pdf', 'desc' => '生成 pdf 格式的数据库字典'],
        ['code' => "8", 'name' => 'update_composer', 'desc' => '更新 composer 包'],
        ['code' => "9", 'name' => 'queue', 'desc' => '检查队列状态'],
        ['code' => "10", 'name' => 'clear_cache', 'desc' => '清空缓存']
    ];

    /**
     * 帮助命令配置
     */
    protected function configure()
    {
        $this->setName('sheep:help')
            ->addArgument('code', Argument::OPTIONAL, "请输入操作编号")
            ->setDescription('sheep 帮助命令');
    }



    /**
     * 全部命令集合
     */
    public function all()
    {
        $this->output->newLine();
        $this->output->writeln("sheep 帮助命令行");
        $this->output->writeln('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
        $this->output->newLine();

        if (!is_dir(runtime_path('storage'))) {
            @mkdir(runtime_path('storage'), 0755, true);
        }

        foreach ($this->commands as $command) {
            $this->output->writeln("[" . $command['code'] . "] " . $command['desc']);
        }

        $this->output->newLine();

        $code = $this->output->ask(
            $this->input,
            '请输入命令代号',
            '0'
        );

        $this->choose($code);
    }


    /**
     * 打开调试模式
     */
    public function openDebug()
    {
        $this->setEnvFilePath();

        $this->setEnvVar('APP_DEBUG', 'true');

        $this->output->writeln("debug 开启成功");
        return true;
    }


    /**
     * 关闭调试模式
     */
    public function closeDebug()
    {
        $this->setEnvFilePath();

        $this->setEnvVar('APP_DEBUG', 'false');

        $this->output->writeln("debug 关闭成功");
        return true;
    }


    /**
     * 重置管理员密码
     */
    public function adminResetPassword()
    {
        $this->output->newLine();
        $this->output->writeln("重置管理员密码");
        $this->output->writeln('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
        $this->output->newLine();

        $account = $this->output->ask(
            $this->input,
            '请输入要重置的管理员账号'
        );

        $admin = null;
        if ($account) {
            $admin = Admin::where('account', $account)->find();
        }

        if (!$admin) {
            $this->output->error("请输入正确的管理员账号");
            return false;
        }

        $password = $this->output->ask(
            $this->input,
            '请输入要设置的密码[6-16]'
        );

        if (empty($password) || strlen($password) < 6 || strlen($password) > 16) {
            $this->output->error("请输入正确的密码");
            return false;
        }

        // 重置密码
        $admin->salt = $admin->salt ?: mt_rand(1000, 9999);
        $admin->password = $admin->encryptPassword($password, $admin->salt);
        $admin->save();

        $this->output->writeln("账号 [" . $admin->account . "] 的密码重置成功");
        return true;
    }



    /**
     * 清除管理员登录失败锁定状态
     */
    public function adminClearLoginFail()
    {
        $this->output->newLine();
        $this->output->writeln("清除管理员登录锁定状态");
        $this->output->writeln('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
        $this->output->newLine();

        $account = $this->output->ask(
            $this->input,
            '请输入要清除的管理员账号'
        );

        $admin = null;
        if ($account) {
            $admin = Admin::where('account', $account)->find();
        }

        if (!$admin) {
            $this->output->error("请输入正确的管理员账号");
            return false;
        }


        // 清空登录失败缓存
        $cacheKey = 'admin:' . $admin->id . ':login';
        (new RateLimiter())->clear($cacheKey);

        $admin->login_fail = 0;
        $admin->save();

        $this->output->writeln("账号 [" . $admin->account . "] 锁定状态清除成功");
        return true;
    }



    /**
     * 生成 markdown 数据库字典
     */
    public function databaseNotesMd()
    {
        $tables = $this->databaseTables();

        // 生成 markdown
        $saveFile = $this->databaseToMd($tables);

        $this->output->writeln("数据库表字段说明生成成功");
        $this->output->writeln("地址：" . $saveFile);
        return true;
    }



    /**
     * 生成 pdf 数据库字典
     */
    public function databaseNotesPdf()
    {
        if (!class_exists(\Parsedown::class) || !class_exists(\Dompdf\Dompdf::class)) {
            $answer = $this->output->confirm(
                $this->input,
                "缺少必要的扩展包，是否安装？"
            );

            if ($answer) {
                $this->output->writeln("开始安装必要扩展包");

                $composerProcess = (new ComposerProcess);
                $composerProcess->setCallback(function ($message) {
                    echo $message;
                });
                $composerProcess->require('erusev/parsedown', 'dompdf/dompdf');

                $this->output->newLine();
                $this->output->writeln("扩展包安装成功，请重新执行命令生成 pdf");
                return true;
            } else {
                $this->output->writeln("已取消");
                return true;
            }
        }

        // 获取数据表
        $tables = $this->databaseTables();

        // 生成 markdown
        $mdPath = $this->databaseToMd($tables);

        // 生成 html
        $htmlPath = $this->databaseToHtml($mdPath);

        // 生成 pdf
        $pdfPath = $this->databaseToPdf($htmlPath);

        $this->output->writeln("数据库表字段说明生成成功");
        $this->output->writeln("地址：" . $pdfPath);
        $this->output->writeln("如果文件中存在乱码，请查看如下文档：");
        return true;
    }



    /**
     * 更新 composer 扩展包
     */
    public function updateComposer()
    {
        $composerProcess = (new ComposerProcess);
        $composerProcess->setCallback(function ($message) {
            echo $message;
        });
        $composerProcess->update();

        $this->output->writeln("composer 包更新成功");
        return true;
    }


    /**
     * 检查队列状态
     */
    public function queue() 
    {
        @unlink(root_path('runtime/storage/queue') . 'sheep.log');
        @unlink(root_path('runtime/storage/queue') . 'sheep-high.log');

        $queue = config('queue');
        $driver = $queue['default'];

        if ($driver == 'sync') {
            $driver = $this->output->choice(
                $this->input,
                '队列驱动配置错误，请选择 database 或者 redis 配置',
                ['database', 'redis'],
                'database'
            );
            
            $install = new Install();
            
            if ($driver == 'redis') {
                try {
                    $install->checkRedis();
                } catch (\Exception $ex) {
                    $this->output->error('[error] ' . $ex->getMessage());

                    $this->output->writeln('请执行如下命令重新配置 redis');
                    $this->output->newLine();
                    $this->output->writeln('php think sheep:install redis_config');
                    $this->output->newLine();
                    return false;
                }
            } else if ($driver == 'database') {
                try {
                    $install->checkDatabase();
                } catch (\Exception $ex) {
                    $this->output->error('[error] ' . $ex->getMessage());

                    $this->output->writeln('请执行如下命令重新配置 数据库');
                    $this->output->newLine();
                    $this->output->writeln('php think sheep:install database_config');
                    $this->output->newLine();
                    return false;
                }
            }

            // 更新 env
            $install->setEnvVar('QUEUE.QUEUE_DRIVER', $driver);
            // 更新配置值
            $install->setConfig('queue.default', $driver);
        }

        $this->output->writeln('当前队列驱动为：' . $driver);
        $this->output->writeln('正在添加测试队列...');
        $this->output->newLine();

        // 添加验证队列
        Queue::push('\sheep\job\Test@sheep', [], 'sheep');       // 普通队列
        Queue::push('\sheep\job\Test@sheepHigh', [], 'sheep-high');     // 高优先级队列

        $this->output->writeln('测试队列添加成功');
        $this->output->writeln('请检查 ' . str_replace('\\', '/', root_path('runtime/storage/queue')) . '目录下是否存在如下文件，并且文件内容为当前测试的时间');
        $this->output->newLine();
        $this->output->writeln(str_replace('\\', '/', root_path('runtime/storage/queue')) . 'sheep.log               // 如果没有该文件，则普通优先级队列未监听');
        $this->output->writeln(str_replace('\\', '/', root_path('runtime/storage/queue')) . 'sheep-high.log          // 如果没有该文件，则高优先级队列未监听');
        $this->output->newLine();

        return true;
    }



    /**
     * 清除管理员登录失败锁定状态
     */
    public function clearCache()
    {
        $this->output->newLine();
        $this->output->writeln("清除缓存");
        $this->output->writeln('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
        $this->output->newLine();

        // $type = $this->output->choice(
        //     $this->input,
        //     '请输入要清除的缓存类型',
        //     ['all' => '全部', 'content' => '内容缓存', 'template' => '模板缓存', 'browser' => '浏览器缓存'],
        //     '全部'
        // );
        // $type = trim($type);        // 去除空格
        // $this->{'clear' . ucfirst($type)}();

        $answer = $this->output->confirm(
            $this->input,
            "确认要清楚缓存吗？"
        );

        if ($answer) {
            $this->clearAll();
            $this->output->writeln("缓存清除成功");
        } else {
            $this->output->writeln("取消");
        }
        return true;
    }
}
